#include <webx/route.h>
#include <dbentity/T_XG_MENU.h>
#include <dbentity/T_XG_GROUP.h>

class GetUserMenu : public webx::ProcessBase
{
protected:
	int process();
};

HTTP_WEBAPP(GetUserMenu)

struct MenuItem : public Object
{
	string id;
	string url;
	string icon;
	string title;
	string folder;
	int termtype = 0;
	int position = 0;

	bool operator < (const MenuItem& obj) const
	{
		return id < obj.id;
	}
	bool operator == (const MenuItem& obj) const
	{
		return id == obj.id;
	}
};

struct GroupItem : public Object
{
	string id;
	vector<string> menus;
	
	bool operator < (const GroupItem& obj) const
	{
		return id < obj.id;
	}
	bool operator == (const GroupItem& obj) const
	{
		return id == obj.id;
	}
};

static int GetMenuSet(set<MenuItem>& dataset)
{
	time_t now;
	static time_t ctime;
	static SpinMutex mutex;
	static set<MenuItem> menuset;

	SpinLocker lk(mutex);

	if (ctime + 60 > time(&now) && Process::GetObject("HTTP_MENU_SET"))
	{
		dataset.insert(menuset.begin(), menuset.end());
	}
	else
	{
		CT_XG_MENU menutab;
		sp<DBConnect> dbconn;

		try
		{
			dbconn = webx::GetDBConnect();
		}
		catch(Exception e)
		{
			return XG_SYSBUSY;
		}

		menuset.clear();
		menutab.init(dbconn);

		if (!menutab.find("ENABLED>0"))
		{
			LogTrace(eERR, "load menu set failed");

			return XG_SYSERR;
		}

		auto check = [](string& text, int& type){
			size_t pos = text.rfind('@');

			if (pos == string::npos) return;

			string tag = stdx::toupper(text.substr(pos));

			if (tag == "@PC")
			{
				text = text.substr(0, pos);
				type = 'P';
			}
			else if (tag == "@MOBILE")
			{
				text = text.substr(0, pos);
				type = 'M';
			}
		};
		
		while (menutab.next())
		{
			MenuItem menu;

			menu.id = menutab.id.val();
			menu.url = menutab.url.val();
			menu.icon = menutab.icon.val();
			menu.title = menutab.title.val();
			menu.folder = menutab.folder.val();
			menu.position = menutab.position.val();

			check(menu.folder, menu.termtype);
			check(menu.title, menu.termtype);
			check(menu.url, menu.termtype);

			menuset.insert(menu);
		}

		Process::SetObject("HTTP_MENU_SET", &menuset);

		dataset.insert(menuset.begin(), menuset.end());

		LogTrace(eINF, "load menu set success");
		
		ctime = now;
	}

	return dataset.size();
}

static int GetGroupSet(set<GroupItem>& dataset)
{
	time_t now;
	static time_t ctime;
	static SpinMutex mutex;
	static set<GroupItem> grpset;

	SpinLocker lk(mutex);

	if (ctime + 60 > time(&now) && Process::GetObject("HTTP_GROUP_SET"))
	{
		dataset.insert(grpset.begin(), grpset.end());
	}
	else
	{
		GroupItem grp;
		CT_XG_GROUP grptab;
		sp<DBConnect> dbconn;

		try
		{
			dbconn = webx::GetDBConnect();
		}
		catch(Exception e)
		{
			return XG_SYSBUSY;
		}

		grpset.clear();
		grptab.init(dbconn);

		if (!grptab.find("ENABLED>0"))
		{
			LogTrace(eERR, "load group set failed");

			return XG_SYSERR;
		}
		
		string val;
		vector<string> vec;
		
		while (grptab.next())
		{
			grp.id = grptab.id.val();
			grp.menus.clear();

			if ((val = grptab.menulist.toString()).length() > 0)
			{
				vec.clear();
				
				if (stdx::split(vec, val, ",") > 0)
				{
					for (size_t i = 0; i < vec.size(); i++)
					{
						if ((val = stdx::trim(vec[i])).length() > 0)
						{
							grp.menus.push_back(val);
						}
					}
				}
			}
			
			grpset.insert(grp);
		}

		Process::SetObject("HTTP_GROUP_SET", &grpset);

		dataset.insert(grpset.begin(), grpset.end());

		LogTrace(eINF, "load group set success");
		
		ctime = now;
	}

	return dataset.size();
}

int GetUserMenu::process()
{
	string user;
	string grouplist;
	set<string> menus;
	set<MenuItem> menuset;
	set<GroupItem> groupset;

	param_string(folder);

	if (GetMenuSet(menuset) < 0)
	{
		LogTrace(eERR, "get menu set failed");
		
		return simpleResponse(XG_SYSERR);
	}

	if (GetGroupSet(groupset) < 0)
	{
		LogTrace(eERR, "get group set failed");
		
		return simpleResponse(XG_SYSERR);
	}

	try
	{
		user = checkLogin();

		grouplist = token->getGrouplist();
	}
	catch(Exception e)
	{
	}

	int res = 0;
	string sqlcmd;
	GroupItem grp;
	vector<string> vec;
	bool mobile = request->isMobile();
	JsonElement arr = json.addArray("list");
	sp<DBConnect> dbconn = webx::GetDBConnect();

	if (grouplist == "system" || grouplist == "header" || grouplist == "footer")
	{
		vec.push_back(grouplist);
	}
	else
	{
		stdx::split(vec, grouplist, ",");

		vec.push_back("public");
	}

	auto checkTermtype = [&](const MenuItem& menu){
		if (mobile)
		{
			if (menu.termtype == 'P') return false;
		}
		else
		{
			if (menu.termtype == 'M') return false;
		}

		return true;
	};

	if (folder.empty())
	{
		vector<MenuItem> ms;

		if (user == "root")
		{
			for (const MenuItem& m : menuset)
			{
				if (m.title.empty())
				{
					for (const MenuItem& n : menuset)
					{
						if (n.title.length() > 0 && n.folder == m.folder && checkTermtype(n))
						{
							ms.push_back(m);

							break;
						}
					}
				}
			}
		}
		else
		{
			for (auto& m : vec)
			{
				if ((grp.id = m).length() > 0)
				{
					MenuItem menu;
					auto it = groupset.find(grp);
					
					if (it == groupset.end()) continue;
					
					for (auto& n : it->menus)
					{
						if ((menu.id = n).length() > 0)
						{
							int num = 0;
							auto it = menuset.find(menu);
							
							if (it == menuset.end()) continue;

							if (it->title.length() > 0)
							{
								menu.folder = it->folder;

								for (auto& item : menuset)
								{
									if (item.folder == menu.folder)
									{
										if (item.title.empty())
										{
											menu = item;
										}
										else if (checkTermtype(item))
										{
											++num;
										}
									}
								}
							}

							if (num > 0 && menus.insert(menu.folder).second) ms.push_back(menu);
						}
					}
				}
			}
		}

		std::sort(ms.begin(), ms.end(), [](const MenuItem& a, const MenuItem& b){
			return a.position < b.position;
		});

		for (auto& menu : ms)
		{
			JsonElement item = arr[res++];

			item["folder"] = menu.folder;
			item["icon"] = menu.icon;
		}
	}
	else
	{
		if (user.length() > 0)
		{
			string dbid;
			string menurl;

			if (folder == "菜单管理")
			{
				menurl = "/menupad?folder=";
				stdx::format(sqlcmd, "SELECT FOLDER,ICON FROM T_XG_MENU WHERE (TITLE IS NULL OR TITLE='') ORDER BY POSITION ASC");
			}
			else if (folder == "我的笔记" || folder == "产品管理" || folder == "我的代码" || folder == "配置文件")
			{
				if (mobile)
				{
					JsonElement item = json["list"][res++];

					item["title"] = folder;
					item["icon"] = "/res/img/menu/note.png";
					item["url"] = "/app/workspace/pub/notelist.htm";
				}
				else
				{
					const char* tabname = "T_XG_NOTE";

					dbid = token->getDataId();

					if (folder == "我的笔记")
					{
						menurl = "/notepad?name=" + stdx::EncodeURL("笔记") + "&folder=";
					}
					else if (folder == "产品管理")
					{
						menurl = "/notepad?name=" + stdx::EncodeURL("产品") + "&deficon=/res/img/note/product.png&folder=";
					}
					else if (folder == "我的代码")
					{
						menurl = "/compile/notepad?name=" + stdx::EncodeURL("代码") + "&deficon=/res/img/note/code.png&folder=";

						tabname = "T_XG_CODE";
					}
					else
					{
						menurl = "/confile/notepad?name=" + stdx::EncodeURL("文件") + "&deficon=/res/img/note/configure.png&folder=";

						tabname = "T_XG_CONF";
					}

					stdx::format(sqlcmd, "SELECT FOLDER,ICON FROM %s WHERE USER='%s' AND (TITLE IS NULL OR TITLE='') ORDER BY POSITION ASC", tabname, user.c_str());
				}
			}

			if (dbid.length() > 0) dbconn = webx::GetDBConnect(dbid);

			if (sqlcmd.length() > 0)
			{
				sqlcmd += webx::GetLimitString(dbconn.get(), 32);

				sp<QueryResult> rs = dbconn->query(sqlcmd);

				if (!rs)
				{
					res = XG_SYSERR;
				}
				else
				{
					sp<RowData> row;

					while (row = rs->next())
					{
						JsonElement item = arr[res++];
						string title = row->getString(0);

						item["title"] = title;
						item["icon"] = row->getString(1);
						item["url"] = menurl + stdx::EncodeURL(title);
					}
				}
			}
		}

		vector<MenuItem> ms;

		if (user == "root")
		{
			for (const MenuItem& m : menuset)
			{
				if (m.title.length() > 0 && m.folder == folder && checkTermtype(m))
				{
					ms.push_back(m);
				}
			}
		}
		else
		{
			for (auto& item : vec)
			{
				if ((grp.id = item).length() > 0)
				{
					MenuItem menu;
					auto it = groupset.find(grp);
					
					if (it == groupset.end()) continue;
					
					for (auto& id : it->menus)
					{
						if ((menu.id = id).length() > 0)
						{
							auto it = menuset.find(menu);
							
							if (it == menuset.end() || it->title.empty()) continue;

							if (app->getRouteSwitch() <= 0)
							{
								string url = CgiMapData::GetKey(it->url);

								if (url == "routelist") continue;

								if (url == "timerlist") continue;
							}

							if (folder == "*" || folder == it->folder)
							{
								if (checkTermtype(*it) && menus.insert(it->title).second) ms.push_back(*it);
							}
						}
					}
				}
			}
		}

		std::sort(ms.begin(), ms.end(), [](const MenuItem& a, const MenuItem& b){
			return a.position < b.position;
		});

		for (auto& m : ms)
		{
			if (mobile && m.icon == "/res/img/menu/addfolder.png") continue;

			JsonElement item = arr[res++];

			item["url"] = m.url;
			item["icon"] = m.icon;
			item["title"] = m.title;
			item["folder"] = m.folder;
		}
	}

	json["user"] = user;
	json["code"] = res;
	out << json;

	return XG_OK;
}